package services

import (
	"cashew.com/cashew_common/configs"
	"cashew.com/cashew_common/constants"
	"cashew.com/cashew_common/utils"
	"cashew.com/cashew_task/dtos"
	"encoding/json"
	"github.com/beego/beego/v2/core/logs"
	"math/rand"
	"strconv"
	"sync"
	"time"
)

func SendUserOfflineLiveMessage() {
	sql := "SELECT region_id FROM main_region_configuration"
	db := utils.GetDB()
	rows, err := db.Queryx(sql)
	if err != nil {
		logs.Error("SendUserOfflineLiveMessage::query main_region_configuration error:", err)
		return
	}

	defer func() {
		err = rows.Close()
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::rows close error:", err)
		}
	}()

	wg := sync.WaitGroup{}
	for rows.Next() {
		var mainRegionId int
		err = rows.Scan(&mainRegionId)
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::scan main_region_configuration error:", err, "mainRegionId:", mainRegionId)
			continue
		}

		if mainRegionId != 2 {
			logs.Info("SendUserOfflineLiveMessage::mainRegionId:", mainRegionId, " not support")
			continue
		}

		go func() {
			wg.Add(1)
			SendUserOfflineLiveMessageByMainRegion(mainRegionId)
			logs.Info("SendUserOfflineLiveMessageByMainRegion finish", "mainRegionId:", mainRegionId)
			wg.Done()
		}()
	}
	logs.Info("SendUserOfflineLiveMessage wait")
	wg.Wait()
	logs.Info("SendUserOfflineLiveMessage finish")
}

func SendUserOfflineLiveMessageByMainRegion(mainRegionId int) {

	// 获取离线用户列表
	offlineUsers := getOfflineUsers(mainRegionId)
	offlineUsersLen := len(offlineUsers)

	if offlineUsersLen == 0 {
		logs.Info("SendUserOfflineLiveMessage::getOfflineUsers empty", "mainRegionId:", mainRegionId)
		return
	}
	logs.Info("offlineUsersLen:", offlineUsersLen, "mainRegionId:", mainRegionId)

	// 获取离线用户的随机消息内容
	contents := getRandomAiScript(mainRegionId, offlineUsersLen)
	contentsLen := len(contents)

	if contentsLen == 0 {
		logs.Error("SendUserOfflineLiveMessage::getRandomAiScript empty", "mainRegionId:", mainRegionId)
		return
	}
	logs.Info("contentLen:", contentsLen, "mainRegionId:", mainRegionId)

	// 获取当前正在直播的主播列表
	liveAnchors := getRandomLiveAnchor(mainRegionId, offlineUsersLen)
	liveAnchorsLen := len(liveAnchors)

	if liveAnchorsLen == 0 {
		logs.Error("SendUserOfflineLiveMessage::getRandomLiveAnchor empty", "mainRegionId:", mainRegionId)
		return
	}
	logs.Info("liveAnchorsLen:", liveAnchorsLen, "mainRegionId:", mainRegionId)

	db := utils.GetDB()

	// 更新离线用户的下次发送时间 并为每个用户分配随机消息内容和随机主播
	for i, _ := range offlineUsers {

		// 本次取消息内容的key 超出消息列表范围则取模
		contentKey := i
		if contentKey >= contentsLen {
			contentKey = i % contentsLen
		}

		// 添加消息内容
		offlineUsers[i].Content = &contents[contentKey]

		// 本次取主播的key 超出主播列表范围则取模
		anchorKey := i
		if anchorKey >= liveAnchorsLen {
			anchorKey = i % liveAnchorsLen
		}

		// 添加主播
		offlineUsers[i].Anchor = &liveAnchors[anchorKey]

		msgUser := offlineUsers[i]

		// 更新离线用户的下次发送时间
		_, err := db.Exec("UPDATE user_offline_live_message SET next_send_time = ?, update_time = ? WHERE id = ? and user_id = ?", msgUser.NextSendTime, msgUser.UpdateTime, msgUser.Id, msgUser.User.UserId)
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::update next_send_time error::userId:", msgUser.User.UserId, "error:", err, "mainRegionId:", mainRegionId)
			continue
		}

		logs.Info("SendUserOfflineLiveMessage userId=", msgUser.User.UserId, "next_send_time:", msgUser.NextSendTime, "update_time:", msgUser.UpdateTime, "content:", msgUser.Content.Msg, "anchorId:", msgUser.Anchor.UserId, "mainRegionId:", mainRegionId)
	}

	// 发送离线消息
	sendOfflineMessages(offlineUsers)
}

// 获取离线用户列表
func getOfflineUsers(mainRegionId int) []dtos.OfflineUser {
	db := utils.GetDB()

	// 获取当前时间的分钟为本轮发送的时间
	nowTime := time.Now().Unix()
	curSendTime := nowTime - (nowTime % 60) + 59 // 向下取整到分钟

	logs.Info("curSendTime:", curSendTime, "mainRegionId:", mainRegionId)

	sql := "SELECT um.id, u.update_time, um.user_id, u.nick, u.head_img, u.age, src.flag_image, u.gender "
	sql += "FROM user_offline_live_message um "
	sql += "LEFT JOIN users u on um.user_id=u.user_id "
	sql += "LEFT JOIN sub_region_configuration src on u.sub_region_id = src.region_id "
	sql += "WHERE um.next_send_time > 0 AND um.next_send_time <= ? AND u.status = ? AND src.main_region_id = ? "
	// 查询本轮需要发送的离线用户
	rows, err := db.Queryx(sql, curSendTime, constants.ANCHOR_OFFLINE, mainRegionId)

	if err != nil {
		logs.Error("SendUserOfflineLiveMessage::query error::error:", err, "mainRegionId:", mainRegionId)
		return nil
	}
	defer func() {
		err = rows.Close()
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::getOfflineUsers::rows close error::error:", err, "mainRegionId:", mainRegionId)
		}
	}()

	type offlineUserRow struct {
		Id         int64  `db:"id"`
		UpdateTime int64  `db:"update_time"`
		UserId     string `db:"user_id"`
		Nick       string `db:"nick"`
		HeadImg    string `db:"head_img"`
		Age        int    `db:"age"`
		FlagImage  string `db:"flag_image"`
		Gender     int    `db:"gender"`
	}

	// 生成待发送的离线用户列表
	var offlineUsers []dtos.OfflineUser
	for rows.Next() {
		row := offlineUserRow{}
		err = rows.StructScan(&row)
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::scan error::error:", err, "mainRegionId:", mainRegionId)
			continue
		}

		offlineUsers = append(offlineUsers, dtos.OfflineUser{
			Id:           row.Id,
			UpdateTime:   row.UpdateTime,
			NextSendTime: getOfflineNextSendTime(nowTime, row.UpdateTime),
			User: &dtos.UserProfile{
				UserId:    row.UserId,
				Nick:      row.Nick,
				HeadImg:   row.HeadImg,
				Age:       row.Age,
				FlagImage: row.FlagImage,
				Gender:    row.Gender,
				Identity:  constants.IDENTITY_NORMAL_USER,
			},
		})
	}

	if len(offlineUsers) == 0 {
		return nil
	}

	return offlineUsers
}

// 获取随机消息列表
func getRandomAiScript(mainRegionId, limit int) []dtos.AiScriptContent {
	db := utils.GetDB()
	rows, err := db.Queryx("SELECT a.type,a.content FROM ai_scripts as a left join ai_scripts_set as aset on a.set_id = aset.set_id WHERE aset.ai_anchor_type = 2 AND aset.status = 0 AND a.stauts = 0 AND a.type=0 ORDER BY RAND() LIMIT " + strconv.Itoa(limit))
	if err != nil {
		logs.Error("getRandomAiScript error:", err, "mainRegionId:", mainRegionId)
		return nil
	}

	defer func() {
		err = rows.Close()
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::getRandomLiveAnchor::rows close error::error:", err, "mainRegionId:", mainRegionId)
		}
	}()

	var contents []dtos.AiScriptContent

	for rows.Next() {
		var contentType int
		var contentJsonStr string
		err = rows.Scan(&contentType, &contentJsonStr)
		if err != nil {
			logs.Error("getRandomAiScript scan error:", err, "mainRegionId:", mainRegionId)
			continue
		}

		content := dtos.AiScriptContent{}

		err = json.Unmarshal([]byte(contentJsonStr), &content)

		if err != nil {
			logs.Error("getRandomAiScript json unmarshal error:", err, "contentJsonStr:", contentJsonStr, "mainRegionId:", mainRegionId)
			continue
		}

		if content.Msg == "" {
			logs.Error("getRandomAiScript json unmarshal error: content.Msg is empty, contentJsonStr:", contentJsonStr, "mainRegionId:", mainRegionId)
			continue
		}

		content.MsgType = contentType

		contents = append(contents, content)
	}

	return contents
}

// 获取随机在线主播列表
func getRandomLiveAnchor(mainRegionId, limit int) []dtos.UserProfile {
	db := utils.GetDB()

	sql := "SELECT als.anchor_id user_id, als.nick, als.head_img, als.age, als.flag_image, als.gender"
	sql += " FROM anchor_live_status als"
	sql += " LEFT JOIN sub_region_configuration src ON als.sub_region_id = src.region_id"
	sql += " WHERE als.live_status=1 AND src.main_region_id=? ORDER BY RAND() LIMIT "
	sql += strconv.Itoa(limit)

	rows, err := db.Queryx(sql, mainRegionId)

	if err != nil {
		logs.Error("getRandomLiveAnchor error:", err, "mainRegionId:", mainRegionId)
		return nil
	}

	defer func() {
		err = rows.Close()
		if err != nil {
			logs.Error("SendUserOfflineLiveMessage::getRandomLiveAnchor::rows close error::error:", err, "mainRegionId:", mainRegionId)
		}
	}()

	var anchors []dtos.UserProfile

	for rows.Next() {
		anchor := dtos.UserProfile{}
		err = rows.StructScan(&anchor)
		if err != nil {
			logs.Error("getRandomLiveAnchor scan error:", err, "mainRegionId:", mainRegionId)
			continue
		}

		if anchor.UserId == "" || anchor.UserId == "0" {
			logs.Error("getRandomLiveAnchor scan error: userId is 0", "mainRegionId:", mainRegionId)
			continue
		}

		anchor.Identity = constants.IDENTITY_NORMAL_USER

		anchors = append(anchors, anchor)
	}

	return anchors
}

// 获取下次发送时间
func getOfflineNextSendTime(nowTime, updateTime int64) int64 {
	offlineTime := nowTime - updateTime // 已经离线多长时间
	var plusTime int64
	if offlineTime <= 10800 { // 3小时内, 下次发送时间随机20分钟到60分钟发送一次
		plusTime = 1200 + rand.Int63n(2400)
	} else if offlineTime <= 86400 { // 24小时内, 下次发送时间随机2小时到6小时发送一次
		plusTime = 7200 + rand.Int63n(14400)
	} else if offlineTime <= 604800 { // 7天内, 下次发送时间随机4小时到12小时发送一次
		plusTime = 14400 + rand.Int63n(28800)
	} else if offlineTime <= 2592000 { // 30天内, 下次发送时间随机12小时到24小时发送一次
		plusTime = 43200 + rand.Int63n(43200)
	} else { // 超过30天, 不再发送
		plusTime = 0
	}

	if plusTime == 0 {
		return 0
	}

	return nowTime + plusTime
}

// 发送离线消息
func sendOfflineMessages(messUsers []dtos.OfflineUser) {

	for _, msgUser := range messUsers {
		if msgUser.User == nil || msgUser.Content == nil || msgUser.Anchor == nil {
			logs.Error("SendUserOfflineLiveMessage::sendOfflineMessages::user or content or anchor is nil, id:", msgUser.Id)
			continue
		}

		// 发送离线消息
		params := dtos.ChatParams{
			UserId:       msgUser.Anchor.UserId,
			Gender:       msgUser.Anchor.Gender,
			ToUserId:     msgUser.User.UserId,
			MsgType:      msgUser.Content.MsgType,
			Msg:          msgUser.Content.Msg,
			Duration:     msgUser.Content.Duration,
			ChatScenario: constants.CHAT_SCENARIO_PRIVATE,
			UserInfo:     msgUser.Anchor,
			ToUserInfo:   msgUser.User,
		}

		ret, err := utils.ApiCall(configs.FreeChatSendMessage, "sama", params)
		logs.Error("SendUserOfflineLiveMessage::sendOfflineMessages::http call url:", configs.FreeChatSendMessage, "params:", utils.ToJsonString(params), "ret:", string(ret), "err:", err)
	}
}
